/**
 * k-proto协议
 * (工具生成，请不要手动修改...)
 */
export namespace KProto {

    let b: any, Coder: any;
    /** 传入k-coder来进行初始化 */
    export function init(kcoder: any) {
        b = new kcoder.KBinary();
        Coder = kcoder.StructCoder;
    }

    const idBufDic: any = {}, tosCoderDic: any = {}, tocCoderDic: any = {};

    /** 加载单个协议结构 */
    export function load(protoId: any, struct: any) {
        let st: any;
        tosCoderDic[protoId] = (st = struct[protoId][0]) ? new Coder(st) : undefined;
        tocCoderDic[protoId] = (st = struct[protoId][1]) ? new Coder(st) : undefined;
        if (!idBufDic[protoId]) {
            const id = protoId.split("_");
            idBufDic[protoId] = b.wStart().wAuint32(id[0]).wAuint32(id[1]).wEnd();
        }
    }

    /** 加载所有协议结构 */
    export function loadAll(struct: any, onCount?: (count: number) => void) {
        let c = 0;
        for (let protoId in struct) {
            load(protoId, struct);
            if (onCount) {
                onCount(++c);
            }
        }
    }

    /** 编码协议id */
    export function encodeId(id: KProtoId) {
        b.wStart().wBuf(idBufDic[id]);
    }

    /** 编码tos协议 */
    export function encodeTos<ID extends KProtoTosNeed>(id: ID, data: KProtoTos[ID]): Uint8Array
    export function encodeTos<ID extends KProtoTosNever>(id: ID): Uint8Array
    export function encodeTos(id: KProtoId, data?: any): Uint8Array {
        tosCoderDic[id]?.encode(data, b);
        return b.wEnd();
    }

    /** 编码toc协议 */
    export function encodeToc<ID extends KProtoTocNeed>(id: ID, data: KProtoToc[ID]): Uint8Array
    export function encodeToc<ID extends KProtoTocNever>(id: ID): Uint8Array
    export function encodeToc(id: KProtoId, data?: any): Uint8Array {
        tocCoderDic[id]?.encode(data, b);
        return b.wEnd();
    }

    /** 解码协议id */
    export function decodeId(buf: Uint8Array) {
        b.rStart(buf);
        return `${b.rAuint32()}_${b.rAuint32()}`;
    }

    /** 解码tos协议 */
    export function decodeTos<ID extends KProtoTosNeed>(id: ID, buf?: Uint8Array): KProtoTos[ID]
    export function decodeTos<ID extends KProtoTosNever>(id: ID, buf?: Uint8Array): void
    export function decodeTos(id: KProtoId, buf?: Uint8Array) {
        return tosCoderDic[id]?.decode(buf || b);
    }

    /** 解码toc协议 */
    export function decodeToc<ID extends KProtoTocNeed>(id: ID, buf?: Uint8Array): KProtoToc[ID]
    export function decodeToc<ID extends KProtoTocNever>(id: ID, buf?: Uint8Array): void
    export function decodeToc(id: KProtoId, buf?: Uint8Array) {
        return tocCoderDic[id]?.decode(buf || b);
    }

    /** 解码协议id后剩下的数据buf */
    export function getDataBuf() {
        return b.rCut(b.rBuf.length - b.rPos);
    }

    const win: any = globalThis || window;
    win["KProtoId"] = { error: "1_0", msg_add: "1_1", joinGame: "2_0", ready: "2_1", entityAdd: "3_0", entityUpdate: "3_1", entityRemove: "3_2", foodEaten: "3_3", focus: "4_0", ctrlRot: "4_1", ctrlSprint: "4_2", updateScreen: "4_3", snakeInfo: "5_0", snakeRemove: "5_1" };

}

declare global {

    /** 协议号 */
    enum KProtoId {
        error = "1_0",
        /** 消息添加 */
        msg_add = "1_1",
        /** 加入游戏 */
        joinGame = "2_0",
        /** 准备好接收数据了 */
        ready = "2_1",
        /** 实体入屏 */
        entityAdd = "3_0",
        /** 实体更新 */
        entityUpdate = "3_1",
        /** 实体离屏 */
        entityRemove = "3_2",
        /** 食物被吃 */
        foodEaten = "3_3",
        /** 相机焦点 */
        focus = "4_0",
        /** 控制朝向 */
        ctrlRot = "4_1",
        /** 控制加速 */
        ctrlSprint = "4_2",
        /** 屏幕变化 */
        updateScreen = "4_3",
        /** 蛇信息 */
        snakeInfo = "5_0",
        /** 蛇移除 */
        snakeRemove = "5_1",
    }

    /** 发往服务端的协议 */
    interface KProtoTos {
        [KProtoId.joinGame]: kp_join_joinGame_tos
        [KProtoId.ready]: never
        [KProtoId.ctrlRot]: kp_player_ctrlRot_tos
        [KProtoId.ctrlSprint]: kp_player_ctrlSprint_tos
        [KProtoId.updateScreen]: kp_player_updateScreen_tos
    }

    type KProtoTosNeed = keyof Pick<KProtoTos, { [key in keyof KProtoTos]: KProtoTos[key] extends never ? never : key }[keyof KProtoTos]>;
    type KProtoTosNever = Exclude<keyof KProtoTos, KProtoTosNeed>;

    /** 发往客户端的协议 */
    interface KProtoToc {
        [KProtoId.error]: kp_com_error_toc
        [KProtoId.msg_add]: kp_com_msg_add_toc
        [KProtoId.joinGame]: kp_join_joinGame_toc
        [KProtoId.ready]: kp_join_ready_toc
        [KProtoId.entityAdd]: kp_entity_entityAdd_toc
        [KProtoId.entityUpdate]: kp_entity_entityUpdate_toc
        [KProtoId.entityRemove]: kp_entity_entityRemove_toc
        [KProtoId.foodEaten]: kp_entity_foodEaten_toc
        [KProtoId.focus]: kp_player_focus_toc
        [KProtoId.snakeInfo]: kp_snake_snakeInfo_toc
        [KProtoId.snakeRemove]: kp_snake_snakeRemove_toc
    }

    type KProtoTocNeed = keyof Pick<KProtoToc, { [key in keyof KProtoToc]: KProtoToc[key] extends never ? never : key }[keyof KProtoToc]>;
    type KProtoTocNever = Exclude<keyof KProtoToc, KProtoTocNeed>;

    interface kp_com_size {
        width: number,
        height: number,
    }

    /** 消息 */
    interface kp_com_msg {
        /** 时间戳 */
        time: number,
        /** 消息 */
        msg: string,
    }

    interface kp_com_error_toc {
        /** 错误码 */
        code: number,
        /** 协议号 */
        protoId: number,
    }

    /** 消息添加 */
    interface kp_com_msg_add_toc {
        /** 消息列表 */
        msgs: kp_com_msg[],
    }

    /** 蛇身实体 */
    interface kp_entity_snakeBody {
        id: number,
        idx: number,
        x: number,
        y: number,
        rot: number,
    }

    /** 蛇实体 */
    interface kp_entity_snake {
        id: number,
        size: number,
        bodys: kp_entity_snakeBody[],
    }

    /** 食物实体 */
    interface kp_entity_food {
        id: number,
        x: number,
        y: number,
        rot: number,
        size: number,
        color?: number,
    }

    /** 被吃的食物 */
    interface kp_entity_eatenFood {
        /** 食物id */
        id: number,
        /** 吃食物的蛇头id */
        eaterId: number,
    }

    /** 实体入屏 */
    interface kp_entity_entityAdd_toc {
        /** 食物列表 */
        foods?: kp_entity_food[],
        /** 蛇列表 */
        snakes?: kp_entity_snake[],
    }

    /** 实体更新 */
    interface kp_entity_entityUpdate_toc {
        /** 食物列表 */
        foods: kp_entity_food[],
        /** 蛇列表 */
        snakes?: kp_entity_snake[],
    }

    /** 实体离屏 */
    interface kp_entity_entityRemove_toc {
        /** 实体id列表 */
        ids: number[],
    }

    /** 食物被吃 */
    interface kp_entity_foodEaten_toc {
        /** 被吃的食物 */
        foods: kp_entity_eatenFood[],
    }

    /** 加入游戏 */
    interface kp_join_joinGame_toc {
        /** 玩家id */
        pid: number,
        /** 世界大小 */
        worldSize: kp_com_size,
    }

    /** 加入游戏 */
    interface kp_join_joinGame_tos {
        /** 蛇名 */
        name: string,
        /** 屏幕 */
        screen: kp_com_size,
    }

    /** 准备好接收数据了 */
    interface kp_join_ready_toc {
        /** 蛇id */
        snakeId: number,
    }

    /** 相机焦点 */
    interface kp_player_focus_toc {
        /** 蛇身id */
        id: number,
    }

    /** 控制朝向 */
    interface kp_player_ctrlRot_tos {
        /** 朝向(弧度值) */
        rot: number,
    }

    /** 控制加速 */
    interface kp_player_ctrlSprint_tos {
        /** 是否加速 */
        isSprint: boolean,
    }

    /** 屏幕变化 */
    interface kp_player_updateScreen_tos {
        screen: kp_com_size,
    }

    /** 蛇信息 */
    interface kp_snake_snake {
        /** 蛇id */
        id: number,
        /** 蛇名 */
        name?: string,
        /** 颜色 */
        colors?: number[],
        /** 分数 */
        score?: number,
        /** 幽灵状态 0:否 1:是 */
        ghost?: number,
    }

    /** 蛇信息 */
    interface kp_snake_snakeInfo_toc {
        /**  1:添加 2:更新 */
        type: number,
        /** 蛇列表 */
        snakes: kp_snake_snake[],
    }

    /** 蛇移除 */
    interface kp_snake_snakeRemove_toc {
        /** id列表 */
        ids: number[],
    }

}